﻿#region Using
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using AspNetInfo.Controls;
using AspNetInfo.Core;
using AspNetInfo.Detectors;
using AspNetInfo.Diagnostics;
using AspNetInfo.Helpers; 
#endregion

namespace AspNetInfo
{
    public partial class AspNetInfo : Page
    {
        #region Properties
        protected EnvironmentPermissions permissions = new EnvironmentPermissions();
        protected IDictionary<string, string> SmtpSettings;
        protected IEnumerable<string> tabs;
        protected  IEnumerable<ITestFixture> testFixtures;
        private IEnumerable<IDetector> detectors; 
        #endregion

        #region Events
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            IPluginProvider pluginProvider = new PluginProvider();
            testFixtures = pluginProvider.GetDiagnosticPlugins();
            foreach (var fixture in testFixtures)
            {
                SetupFixture(fixture);
            }
            detectors = pluginProvider.GetDetectorPlugins();
            tabs = detectors.Select(d => d.TabName).Distinct();
            SmtpSettings = GetSmtpSettings();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            RegisterCssResource("AspNetInfo.Resources.main.css");
            Page.ClientScript.RegisterClientScriptResource(typeof(AspNetInfo), "AspNetInfo.Resources.AspNetInfo.js");

            if (!Page.IsPostBack)
            {
                RenderPermissionLevelAlert(permissions);
            }
        }

        protected void rptTestFixtures_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            RepeaterItem item = e.Item;
            if ((item.ItemType == ListItemType.Item) ||
                (item.ItemType == ListItemType.AlternatingItem))
            {
                var rptTests = (Repeater)item.FindControl("rptTests");
                var fixture = (ITestFixture)item.DataItem;
                rptTests.DataSource = fixture.Tests;
                rptTests.DataBind();
            }
        }
        #endregion

        #region Protected Members
        /// <summary>
        /// Creates a variable friendly name from a human friend name.
        /// </summary>
        /// <param name="tab">Human friendly name</param>
        /// <returns>Variable friendly name with non-alphanumeric characters and leading digits removed.</returns>
        protected string GetTabId(string tab)
        {
            var id = Regex.Replace(tab, @"[\W]", String.Empty);
            return Regex.Replace(id, @"^\d*", string.Empty).ToLower();
        }

        protected IEnumerable<IDetector> GetDetectorsByTab(string tab)
        {
            return detectors.Where(d => d.TabName == tab);
        }

        /// <summary>
        /// Get path of an image that is an embedded resource.  The returns value
        /// can be bound directory to a 'src' attribute.
        /// </summary>
        /// <param name="image">Filename of image from the /Resources directory.</param>
        /// <returns>WebResource.axd path that returns the image.</returns>
        protected string GetImageResource(string image)
        {
            return Page.ClientScript.GetWebResourceUrl(typeof(AspNetInfo), "AspNetInfo.Resources." + image);
        }

        /// <summary>
        /// Register a CSS sheet that is an embedded resource as a <link /> in the page <head />
        /// </summary>
        /// <param name="resourceName">The name of the embedded CSS sheet resource</param>
        protected void RegisterCssResource(string resourceName)
        {
            var includeTemplate = "<link rel='stylesheet' text='text/css' href='{0}' />";
            var includeLocation = Page.ClientScript.GetWebResourceUrl(typeof(AspNetInfo), resourceName);
            var include = new LiteralControl(String.Format(includeTemplate, includeLocation));
            ((System.Web.UI.HtmlControls.HtmlHead)Page.Header).Controls.Add(include);
        }

        /// <summary>
        /// Use the GridView control to render a DataTable as an HTML table. 
        /// Cells with a boolean value are given CssClass 'true' or 'false'
        /// The first cell is given the CSS class 'info_name'
        /// </summary>
        /// <param name="table">DataTable to render as HTML.</param>
        /// <returns>StringBuilder containing the HTML for the table.</returns>
        protected StringBuilder RenderDetectorGridView(DataTable table)
        {
            var grid = new GridView();
            var result = new StringBuilder();
            var writer = new StringWriter(result);
            var htmlWriter = new HtmlTextWriter(writer);
            grid.CssClass = "info_table";
            grid.RowDataBound +=
                (o, e) =>
                {
                    if (e.Row.RowType != DataControlRowType.DataRow) return;
                    foreach (TableCell cell in e.Row.Cells)
                    {
                        bool cellValue = false;
                        cell.CssClass = bool.TryParse(cell.Text, out cellValue) ? cell.Text.ToLower() : string.Empty;
                    }
                    e.Row.Cells[0].CssClass = "info_name";
                };
            grid.DataSource = table;
            grid.DataBind();
            grid.RenderControl(htmlWriter);
            return result;
        } 
        #endregion

        #region Private Members
        private static bool SetupFixture(ITestFixture fixture)
        {
            try
            {
                fixture.Setup();
            }
            catch (Exception exc)
            {
                fixture.Error = exc;
                return false;
            }

            return true;
        }

        private void RenderPermissionLevelAlert(EnvironmentPermissions permissions)
        {
            AspNetHostingPermissionLevel permissionLevel = permissions.TrustLevel;

            if (permissionLevel <= AspNetHostingPermissionLevel.Medium)
            {
                alertTop.Text = String.Format("Hosting Permission Level is set to <strong>{0}</strong> trust.  Considerable functionality is not available at this trust level.", Enum.GetName(typeof(AspNetHostingPermissionLevel), permissionLevel));
                alertTop.MessageType = JQueryUIAlert.JQueryMessageType.Info;
                alertTop.Visible = true;
            }
            else
            {
                alertTop.Visible = false;
            }
        }

        private IDictionary<string, string> GetSmtpSettings()
        {
            var settings = new Dictionary<string, string>();
            var smtp = new SmtpClient();

            settings.Add("Host", smtp.Host);
            settings.Add("Port", smtp.Port.ToString());
            settings.Add("DeliveryMethod", smtp.DeliveryMethod.ToString());
            settings.Add("PickupDirectoryLocation", smtp.PickupDirectoryLocation);
            settings.Add("EnableSsl", smtp.EnableSsl.ToString());
            settings.Add("UseDefaultCredentials", smtp.UseDefaultCredentials.ToString());
            settings.Add("Timeout", smtp.Timeout.ToString());
            settings.Add("Username", "N/A");
            settings.Add("Password", "N/A");
            settings.Add("From", "N/A");

            return settings;
        }

        #endregion

        #region Web Methods

        [WebMethod]
        public static TestResult ExecuteDiagnostic(string testName)
        {
            IPluginProvider pluginProvider = new PluginProvider();
            var fixtures = pluginProvider.GetDiagnosticPlugins();

            foreach (var fixture in fixtures)
            {
                if (!SetupFixture(fixture)) continue;
                foreach (var test in fixture.Tests)
                {
                    if (test.Name == testName)
                    {
                        TestResult result = null;
                        try
                        {
                            result = test.Execute();
                            result.Name = testName;
                        }
                        catch (Exception exc)
                        {
                            result = new TestResult { Status = TestStatus.Failed, Name = testName };
                            result.Messages.Add(exc.Message);
                        }

                        return result;
                    }
                }
            }

            throw new ArgumentException(testName + " is not a valid test name.", "testName");

        }

        [WebMethod]
        public static string TestEmail(string from, string to, string format, string subject, string message,
            bool customSmtp, string host, int port, string deliveryMethod, string pickupDir,
            bool defaultCreds, string username, string password)
        {
            string smtpResult = string.Empty;
            try
            {
                SmtpClient smtp = null;
                if (customSmtp)
                {
                    smtp = EmailTestor.GetCustomSmtp
                        (host,
                        port,
                        (SmtpDeliveryMethod)Enum.Parse(typeof(SmtpDeliveryMethod), deliveryMethod),
                        pickupDir,
                        10000,
                        false);
                    if (defaultCreds == false)
                        smtp = EmailTestor.SetSmtpCredentials(smtp, username, password);
                }
                else
                    smtp = EmailTestor.GetDefaultSmtp();

                EmailTestor.SendEmail
                    (from,
                    to,
                    subject,
                    message,
                    format == "html",
                    smtp);

                smtpResult = "Test email successfully sent.  Please verify that the email arrived at " + to + ".";
            }
            catch (Exception ex)
            {
                smtpResult = "ERROR: " + ex.Message;
            }
            return smtpResult;
        } 
        #endregion
    }
}
